# -*- coding: utf-8 -*-
"""
Module Description: 忘性列表
Date: 2016/9/9
Author: Song Wenwu
"""
from collections import MutableSequence


class ForgetfulList(MutableSequence):
    """
    有容量限制的列表，超出容量时前面(从 0 索引开始)的元素将被清除。
    """

    def __init__(self, capacity=1024):
        """初始化
        :param capacity: 容量限制 (=1024)
        """
        super(ForgetfulList, self).__init__()
        self.capacity = capacity
        self.forgotten = 0
        self.container = []

    def _validslice(self, i):
        """有效化 slice ，忽略已遗忘的索引。
        :type i: slice
        :rtype: slice
        """
        def safe(x):
            if x is None:
                return None

            return x if x < 0 else max(0, x - self.forgotten)

        return slice(safe(i.start),
                     safe(i.stop),
                     i.step)

    def _validindex(self, i):
        """有效化索引， 对已遗忘的索引，根据其类型：
             slice 时忽略
             int 时抛出 IndexError
        :type i: slice | int
        :rtype: type(i)
        """
        if isinstance(i, slice):
            return self._validslice(i)

        if i < 0:
            return i
        i -= self.forgotten
        if i < 0:
            raise IndexError('forgotten')
        return i

    def forget(self):
        """清除部分前面的元素以遵循容量限制。"""
        r = len(self.container) - self.capacity
        if r > 0:
            del self.container[:r]
            self.forgotten += r

    def __len__(self):
        # 长度包含已遗忘的元素
        return len(self.container) + self.forgotten

    def __getitem__(self, i):
        return self.container[self._validindex(i)]

    def __setitem__(self, i, v):
        self.container[self._validindex(i)] = v

    def __delitem__(self, i):
        del self.container[self._validindex(i)]

    def __str__(self):
        return repr(self.container)

    def __iter__(self):
        return iter(self.container)

    def insert(self, i, v):
        self.container.insert(self._validindex(i), v)
        self.forget()

    def append(self, v):
        self.container.append(v)
        self.forget()

    def extend(self, it):
        self.container.extend(it)
        self.forget()
